/**
 * Copyright(c) 2011
 *
 * Licensed under the terms of the Open Source LGPL 3.0
 * http://www.gnu.org/licenses/lgpl.html
 * @author Greivin Britton, brittongr@gmail.com
 *     
 * @changes
 * No currency symbol by default    
 * No decimalPrecision in config
 * Supporting any character as thousand separator
 * Improved getFormattedValue
 * Removed unnecessary code to create format template, now using float.toFixed(this.decimalPrecission)    
 */
Ext.ux.NumericField = function(config) {
    Ext.ux.NumericField.superclass.constructor.call(this, Ext.apply(config));
    //Only if thousandSeparator doesn't exists is assigned when using decimalSeparator as the same as thousandSeparator
    if (this.useThousandSeparator && this.decimalSeparator == ',' && Ext.isEmpty(config.thousandSeparator)) {
        this.thousandSeparator = '.';
    } else {
        if (this.allowDecimals && this.thousandSeparator == '.' && Ext.isEmpty(config.decimalSeparator)) {
            this.decimalSeparator = ',';
        }
    }
    this.onFocus = this.onFocus.createSequence(this.onFocus);
};

Ext.extend(Ext.ux.NumericField, Ext.form.NumberField, {
    currencySymbol: null,
    currencySymbolPosition: 'before',
    useThousandSeparator: true,
    thousandSeparator: ',',
    alwaysDisplayDecimals: false,
    numberFieldAlign: 'right',

    /**
     * Override initComponent to check valid arguments
     */
    initComponent: function() {
        if ((this.currencySymbolPosition != 'before') && (this.currencySymbolPosition != 'after')) {
            this.currencySymbolPosition = 'before';
        }
        if ((this.numberFieldAlign != 'left') && (this.numberFieldAlign != 'right')) {
            this.numberFieldAlign = 'left';
        }
        if (this.useThousandSeparator && Ext.isEmpty(this.thousandSeparator)) {
            this.thousandSeparator = ',';
        }
        if ((this.allowDecimals) && Ext.isEmpty(this.decimalSeparator)) {
            this.decimalSeparator = '.';
        }
        if ((this.allowDecimals) && (this.thousandSeparator == this.decimalSeparator)) {
            throw (this.name + ' [NumberFormatException]: thousandSeparator must be different from decimalSeparator.');
        }

        var initialConfig = {
            style: 'text-align:' + this.numberFieldAlign + ';'
        };
        Ext.apply(this, Ext.apply(this.initialConfig, initialConfig));
        Ext.ux.NumericField.superclass.initComponent.call(this, arguments);
    },
    onRender: function() {
        Ext.ux.NumericField.superclass.onRender.apply(this, arguments);
        this.hiddenField = this.el.insertSibling({
            tag: 'input',
            type: 'hidden',
            name: this.name,
            value: (this.isValid() ? this.getValue() : '')
        });
        this.hiddenName = name;
        this.el.dom.removeAttribute('name');
    },
    setValue: function(v) {
        Ext.ux.NumericField.superclass.setValue.call(this, v);
        this.setRawValue(this.getFormattedValue(this.getValue()));
        this.hiddenField.dom.value = this.getValue();
    },
    /**
     * No more using Ext.util.Format.number, Ext.util.Format.number in ExtJS versions
     * less thant 4.0 doesn't allow to use a different thousand separator than "," or "."
     * @param {Number} v
     */
    getFormattedValue: function(v) {
        if (Ext.isEmpty(v) || !this.hasFormat()) {
            return v;
        } else {
            var neg = null;
            v = (neg = v < 0) ? v * -1 : v;
            v = this.allowDecimals && this.alwaysDisplayDecimals ? v.toFixed(this.decimalPrecision) : v;
            if (this.useThousandSeparator) {
                v = String(v);
                var ps = v.split('.');
                ps[1] = ps[1] ? ps[1] : null;
                var whole = ps[0];
                var r = /(\d+)(\d{3})/;
                var ts = this.thousandSeparator;
                while (r.test(whole)) {
                    whole = whole.replace(r, '$1' + ts + '$2');
                }
                v = whole + (ps[1] ? this.decimalSeparator + ps[1] : '');
            }
            if (this.currencySymbolPosition == 'before') {
                return String.format('{0}{1}{2}', (Ext.isEmpty(this.currencySymbol) ? '' : this.currencySymbol + ' '), (neg ? '-' : ''), v);
            } else {
                return String.format('{0}{1}{2}', (neg ? '-' : ''), v, (Ext.isEmpty(this.currencySymbol) ? '' : ' ' + this.currencySymbol));
            }
        }
    },
    /**
     * overrides parseValue to remove the format applied by this class
     */
    parseValue: function(v) {
        //Replace the currency symbol and thousand separator
        return Ext.ux.NumericField.superclass.parseValue.call(this, this.removeFormat(v));
    },
    /**
     * Remove only the format added by this class to let the superclass validate with it's rules.
     * @param {Object} v
     */
    removeFormat: function(v) {
        v = (v.replace(this.currencySymbol, '')).trim();
        v = this.useThousandSeparator ? v.replace(new RegExp('[' + this.thousandSeparator + ']', 'g'), '') : v;
        return v;
    },
    /**
     * Remove the format before validating the the value.
     * @param {Number} v
     */
    getErrors: function(v) {
        num = this.getValue();
        var errors = [];

        if (num.length < 1 || num === this.emptyText) {
            if (this.allowBlank) {
                return errors;
            } else {
                errors.push(this.blankText);
            }
        }
        if (isNaN(num)) {
            errors.push(String.format(this.nanText, num));
        }
        if (num < this.minValue) {
            errors.push(String.format(this.minText, this.minValue));
        }
        if (num > this.maxValue) {
            errors.push(String.format(this.maxText, this.maxValue));
        }
        return errors;
    },
    
    hasFormat: function() {
        return this.decimalSeparator != '.' || this.useThousandSeparator == true || !Ext.isEmpty(this.currencySymbol) || this.alwaysDisplayDecimals;
    },
    
    /**
     * Display the numeric value with the fixed decimal precision and without the format using the setRawValue, don't need to do a setValue because we don't want a double
     * formatting and process of the value because beforeBlur perform a getRawValue and then a setValue.
     */
    onFocus: function() {
        this.setRawValue(this.removeFormat(this.getRawValue()));
    }
});